﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

/** 
 ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
 * Description: 
 * Author: Heller (HellerSong@outlook.com)
 * CreationTime: 4/10/2015 7:21:25 AM
 ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 
 **/
namespace DevGrammar.Inheritance
{
	#region Abstract Class and Interface
	//接口和抽象类的区别在于使用动机。使用抽象类是为了代码的复用，而使用接口是为了实现多态
	#endregion

	#region Enumerate: 枚举类型中声明的第一个枚举成员默认值为0， 以后的成员+1
	public enum Gender { Male, Female, Unknow };
	#endregion

	#region Struct of Student
	public struct Student
	{
		public string name;
		public int age;
		public Gender gender;

		// If it is struct, you must give the constructor with arguments
		public Student(string name, int age, Gender sex)
		{
			this.name = name;
			this.age = age;
			this.gender = sex;
		}


		public void stuSayHello()
		{
			Console.WriteLine("My Name is {0}, my age is {1}, and my sex is {2}.", name, age, gender);
		}
	}
	#endregion

	abstract class Heart
	{
		//public string humanNature;
		public abstract void DetectHumanNature();
	}

	public class HumanBase
	{
		public string name;
		public Gender sex;

		// If you want call parent method, please use: base.methodName();

		#region Virsual Method
		/*
         * 只有虚方法才能在派生类中重写
         * C#中，函数默认不是虚拟的，遵循C++的方式。除非显示制定，否则不能重写
         * Java中，所有抽象类中的函数都是虚拟的
         */
		public virtual void SayHello() { }
		#endregion
	}

	public class Person : HumanBase //类前面加public，涉及到程序集和命名空间的问题
	{
		// 数据成员包含：字段、常量、事件
		//const常量的定义

		//static类，不能被实例化，一般都是工具类，用来实现一些函数库。
		public static string HumanNature = "Evil";  //static 与具体实例无关

		#region Property
		// Property is word capitalized, and the fist letter of an segment is lowercase.
		// Property role: can do illegal value control; can set read-only(only 'get' or private set).
		public string Name  // 简化的属性写法
		{
			get;    // 没有字段, 编译器自动帮我们生成私有字段和set、get代码块
			set;     //private int <Name>k__BackingField;
		}
		private int age;
		public int Age  //字段与属性的区别在于属性可以进行非法值的控制 
		{
			set
			{
				if (value < 0)
					return;
				this.age = value;
			}
			get
			{
				return this.age;
			}
		}
		public Gender Gender { get; set; }
		public int Height { get; private set; }     // Read only segment.
		#endregion

		#region Constructor
		public Person()     // None parameter Constructor, if no, will help create by default
		{ }
		public Person(string name, Gender sex)
		{
			this.name = name;
			this.sex = sex;
		}
		#endregion


		#region Static Method
		public static void DetectHumanNature()
		{
			//在satic方法中可以调用其它的staic成员，但是不能调用非static成员。
			//在非static方法中可以调用static成员
			Console.WriteLine("The innate nature of human is: {0}" + Person.HumanNature);
		}
		#endregion

		#region Method Override
		public override string ToString()      // Override the System.Object method ToString()
		{
			return "My name is " + Name + ", my age is " + Age + ", and my gender is " + Gender;
		}
		#endregion

		#region Method Overloading
		// Condirion: Differ of argument type and number. 
		// static void SayHello(string name);
		// staitc int SayHello(string name);
		// This is wrong. none related with return value.
		public void SayHello(string name)
		{
			Console.WriteLine("Hello " + this.Name + ",  and my age is: " + this.Age);
		}
		#endregion
	}




	[TestClass]
	public class TestInheritance
	{
		[TestMethod]
		public void TestMethod1()
		{

			/*我的理解：不论是“值类型与引用类型”， “结构与类” 都是堆栈和堆的区别。
			 * 堆栈是机器自动释放的，堆是由GC托管的
			 * 研究的思路都是拿两个变量来讨论，改变一个，看另一个的变化。
			*/
			#region 值类型和引用类型总结
			/*
             * 1.值类型：存储在堆栈中，变量名即首地址，读写操作的是这块内存区域。
             * 2.引用类型：存储在堆中，是数据的引用或指针（类、接口、数组和字符串）。
             * 引用类型创建过程：（1）在栈上创建一个引用变量；（2）在堆上创建对象本身，再把内存句柄（内存首地址）赋值给引用变量。
             *
             * 两者区别的总结：
             *    值类型继承自System.ValueType， 引用类型继承自System.Object；
             *    栈的内存分配是自动释放，而堆在.Net中有GC（Garbage Collector）来释放；
             *    引用可以多个指针指向同一个堆空间
             */

			//在使用Styring类型时，一定要注意重新赋值！(String 和 string一样)
			String str = "This is a Test";
			str.Replace("T", "?");      //Replace，区别大小写而替换（不会替换小写‘t’）
			Console.WriteLine(str);
			#endregion

			#region 结构和类的区别总结和实例探索
			/*结构体，传递内容是位于堆栈区的内容；
             * 类，传递内容是位于托管内存的位置；
             * 共性：定义带参构造函数，通过这些参数给各自的字段赋值或初始化；
             * 小区别：类中可以定义默认无参构造函数，而在结构体中不能定义默认的无参构造函数。
            */

			//实例化类
			Person Liuxiang = new Person();  //无参数的构造函数实例化的对象
			Liuxiang.Name = "Liu Xiang";
			Liuxiang.Age = 30;
			Liuxiang.Gender = Gender.Male;
			Liuxiang.SayHello();
			//声明另一个实例
			Person LXSon = Liuxiang;
			LXSon.Age = 10;
			//查看类 LiuXiang 和 LXSon中字段的值
			Console.WriteLine("LiuXiang's  Age  is {0}", Liuxiang.Age.ToString());  //10
			Console.WriteLine("LXSon's  Age  is {0}", LXSon.Age.ToString());       //10
			Console.WriteLine();

			//实例化结构体
			Student YaoMing = new Student("Yao Ming", 33, Gender.Male);
			YaoMing.stuSayHello();
			Student YMSon = YaoMing;
			YMSon.age = 13;
			//查看结构体中 YaoMing 和 YMSon中字段的值
			Console.WriteLine("YaoMing's  Age  is {0}", YaoMing.age.ToString());    //33
			Console.WriteLine("YMSon's  Age  is {0}", YMSon.age.ToString());        //13
			#endregion
		}
	}
}
